import ffmpeg
import os
import uuid
import logging
import subprocess

class VideoTools:
    """视频处理工具类，专注于核心视频处理功能"""
    
    def __init__(self):
        """初始化视频工具"""
        self.supported_video_formats = ['mp4', 'avi', 'mov', 'mkv', 'wmv', 'flv', 'webm']
    
    def convert_format(self, video_path, target_format, output_dir):
        """
        转换视频格式
        
        Args:
            video_path (str): 视频文件路径
            target_format (str): 目标格式
            output_dir (str): 输出目录
            
        Returns:
            str: 输出视频文件路径
        """
        try:
            # 确保输出目录存在
            os.makedirs(output_dir, exist_ok=True)
            
            output_filename = f"converted_{uuid.uuid4().hex[:8]}.{target_format}"
            output_path = os.path.join(output_dir, output_filename)
            
            # 使用FFmpeg转换格式
            stream = ffmpeg.input(video_path)
            
            # 根据目标格式设置编码参数
            if target_format == 'mp4':
                stream = ffmpeg.output(stream, output_path, vcodec='libx264', acodec='aac')
            elif target_format == 'avi':
                stream = ffmpeg.output(stream, output_path, vcodec='libxvid', acodec='mp3')
            elif target_format == 'mov':
                stream = ffmpeg.output(stream, output_path, vcodec='libx264', acodec='aac')
            elif target_format == 'mkv':
                stream = ffmpeg.output(stream, output_path, vcodec='libx264', acodec='aac')
            elif target_format == 'webm':
                stream = ffmpeg.output(stream, output_path, vcodec='libvpx', acodec='libvorbis')
            else:
                stream = ffmpeg.output(stream, output_path)
            
            ffmpeg.run(stream, overwrite_output=True, quiet=True)
            
            # 验证输出文件是否存在
            if not os.path.exists(output_path):
                raise Exception(f"FFmpeg处理完成但输出文件不存在: {output_path}")
            
            return output_path
        except Exception as e:
            raise Exception(f"转换格式失败: {str(e)}")
    
    def compress_video(self, video_path, output_dir, quality='medium'):
        """
        压缩视频
        
        Args:
            video_path (str): 视频文件路径
            output_dir (str): 输出目录
            quality (str): 压缩质量 ('low', 'medium', 'high')
            
        Returns:
            str: 输出视频文件路径
        """
        try:
            # 确保输出目录存在
            os.makedirs(output_dir, exist_ok=True)
            
            output_filename = f"compressed_{uuid.uuid4().hex[:8]}.mp4"
            output_path = os.path.join(output_dir, output_filename)
            
            # 根据质量设置比特率
            quality_settings = {
                'low': '500k',
                'medium': '1000k',
                'high': '2000k'
            }
            
            bitrate = quality_settings.get(quality, '1000k')
            
            stream = ffmpeg.input(video_path)
            stream = ffmpeg.output(stream, output_path, vcodec='libx264', 
                                 video_bitrate=bitrate, acodec='aac', audio_bitrate='128k')
            ffmpeg.run(stream, overwrite_output=True, quiet=True)
            
            # 验证输出文件是否存在
            if not os.path.exists(output_path):
                raise Exception(f"FFmpeg处理完成但输出文件不存在: {output_path}")
            
            return output_path
        except Exception as e:
            raise Exception(f"压缩视频失败: {str(e)}")
    
    def get_video_info(self, video_path):
        """
        获取视频信息
        
        Args:
            video_path (str): 视频文件路径
            
        Returns:
            dict: 视频信息
        """
        try:
            probe = ffmpeg.probe(video_path)
            
            # 获取视频流信息
            video_stream = next((stream for stream in probe['streams'] if stream['codec_type'] == 'video'), None)
            audio_stream = next((stream for stream in probe['streams'] if stream['codec_type'] == 'audio'), None)
            
            info = {
                'format': probe['format']['format_name'],
                'duration': float(probe['format']['duration']),
                'size': int(probe['format']['size']),
                'bitrate': int(probe['format']['bit_rate'])
            }
            
            if video_stream:
                info.update({
                    'width': int(video_stream['width']),
                    'height': int(video_stream['height']),
                    'video_codec': video_stream['codec_name'],
                    'video_fps': eval(video_stream['r_frame_rate'])
                })
            
            if audio_stream:
                info.update({
                    'audio_codec': audio_stream['codec_name'],
                    'audio_channels': int(audio_stream['channels']),
                    'audio_sample_rate': int(audio_stream['sample_rate'])
                })
            
            return info
        except Exception as e:
            raise Exception(f"获取视频信息失败: {str(e)}")
    
    def trim_video(self, video_path, start_time, end_time, output_dir):
        """
        裁剪视频
        
        Args:
            video_path (str): 视频文件路径
            start_time (str): 开始时间，格式为 "HH:MM:SS"
            end_time (str): 结束时间，格式为 "HH:MM:SS"
            output_dir (str): 输出目录
            
        Returns:
            str: 输出视频文件路径
        """
        try:
            # 确保输出目录存在
            os.makedirs(output_dir, exist_ok=True)
            
            output_filename = f"trimmed_{uuid.uuid4().hex[:8]}.mp4"
            output_path = os.path.join(output_dir, output_filename)
            
            # 计算持续时间
            start_seconds = self._time_to_seconds(start_time)
            end_seconds = self._time_to_seconds(end_time)
            duration = end_seconds - start_seconds
            
            if duration <= 0:
                raise ValueError("结束时间必须大于开始时间")
            
            # 使用FFmpeg裁剪视频
            stream = ffmpeg.input(video_path, ss=start_time, t=duration)
            stream = ffmpeg.output(stream, output_path, vcodec='copy', acodec='copy')
            ffmpeg.run(stream, overwrite_output=True, quiet=True)
            
            # 验证输出文件是否存在
            if not os.path.exists(output_path):
                raise Exception(f"FFmpeg处理完成但输出文件不存在: {output_path}")
            
            return output_path
        except Exception as e:
            raise Exception(f"裁剪视频失败: {str(e)}")
    
    def _time_to_seconds(self, time_str):
        """
        将时间字符串转换为秒数
        
        Args:
            time_str (str): 时间字符串，格式为 "HH:MM:SS"
            
        Returns:
            int: 秒数
        """
        try:
            parts = time_str.split(':')
            if len(parts) != 3:
                raise ValueError(f"无效的时间格式: {time_str}")
            
            hours = int(parts[0])
            minutes = int(parts[1])
            seconds = int(parts[2])
            
            return hours * 3600 + minutes * 60 + seconds
        except Exception as e:
            raise ValueError(f"解析时间失败: {time_str}, 错误: {str(e)}")
    
    def merge_videos(self, video_paths, output_dir):
        """
        合并多个视频文件
        
        Args:
            video_paths (list): 视频文件路径列表
            output_dir (str): 输出目录
            
        Returns:
            str: 输出视频文件路径
        """
        try:
            # 确保输出目录存在
            os.makedirs(output_dir, exist_ok=True)
            
            output_filename = f"merged_video_{uuid.uuid4().hex[:8]}.mp4"
            output_path = os.path.join(output_dir, output_filename)
            
            # 创建FFmpeg输入流
            inputs = []
            for video_path in video_paths:
                inputs.append(ffmpeg.input(video_path))
            
            # 合并视频
            merged = ffmpeg.concat(*inputs, v=1, a=1)
            stream = ffmpeg.output(merged, output_path, vcodec='libx264', acodec='aac')
            ffmpeg.run(stream, overwrite_output=True, quiet=True)
            
            # 验证输出文件是否存在
            if not os.path.exists(output_path):
                raise Exception(f"FFmpeg处理完成但输出文件不存在: {output_path}")
            
            return output_path
        except Exception as e:
            raise Exception(f"合并视频失败: {str(e)}")
    
    def change_video_speed(self, video_path, speed_factor, output_dir):
        """
        改变视频播放速度
        
        Args:
            video_path (str): 视频文件路径
            speed_factor (float): 速度倍数，1.0为正常速度，2.0为2倍速，0.5为0.5倍速
            output_dir (str): 输出目录
            
        Returns:
            str: 输出视频文件路径
        """
        try:
            # 确保输出目录存在
            os.makedirs(output_dir, exist_ok=True)
            
            output_filename = f"speed_changed_{uuid.uuid4().hex[:8]}.mp4"
            output_path = os.path.join(output_dir, output_filename)
            
            # 使用FFmpeg改变视频速度
            stream = ffmpeg.input(video_path)
            stream = ffmpeg.output(stream, output_path, 
                                 filter_complex=f'setpts={1/speed_factor}*PTS,atempo={speed_factor}',
                                 vcodec='libx264', acodec='aac')
            ffmpeg.run(stream, overwrite_output=True, quiet=True)
            
            # 验证输出文件是否存在
            if not os.path.exists(output_path):
                raise Exception(f"FFmpeg处理完成但输出文件不存在: {output_path}")
            
            return output_path
        except Exception as e:
            raise Exception(f"改变视频速度失败: {str(e)}")
    
    def rotate_video(self, video_path, angle, output_dir):
        """
        旋转视频
        
        Args:
            video_path (str): 视频文件路径
            angle (int): 旋转角度，90、180、270
            output_dir (str): 输出目录
            
        Returns:
            str: 输出视频文件路径
        """
        try:
            # 确保输出目录存在
            os.makedirs(output_dir, exist_ok=True)
            
            output_filename = f"rotated_{uuid.uuid4().hex[:8]}.mp4"
            output_path = os.path.join(output_dir, output_filename)
            
            # 验证角度
            if angle not in [90, 180, 270]:
                raise ValueError("角度必须是90、180或270")
            
            # 使用FFmpeg旋转视频
            stream = ffmpeg.input(video_path)
            stream = ffmpeg.output(stream, output_path, 
                                 filter_complex=f'transpose={angle//90}',
                                 vcodec='libx264', acodec='aac')
            ffmpeg.run(stream, overwrite_output=True, quiet=True)
            
            # 验证输出文件是否存在
            if not os.path.exists(output_path):
                raise Exception(f"FFmpeg处理完成但输出文件不存在: {output_path}")
            
            return output_path
        except Exception as e:
            raise Exception(f"旋转视频失败: {str(e)}") 
    
    def add_background_music(self, video_path, music_path, output_dir, volume_ratio=0.3, loop_music=True):
        """
        为视频添加背景音乐
        
        Args:
            video_path (str): 视频文件路径
            music_path (str): 背景音乐文件路径
            output_dir (str): 输出目录
            volume_ratio (float): 背景音乐音量比例，0.0-1.0，默认0.3
            loop_music (bool): 是否循环播放背景音乐，默认True
            
        Returns:
            str: 输出视频文件路径
        """
        try:
            # 确保输出目录存在
            os.makedirs(output_dir, exist_ok=True)
            
            output_filename = f"video_with_bg_music_{uuid.uuid4().hex[:8]}.mp4"
            output_path = os.path.join(output_dir, output_filename)
            
            # 获取视频信息
            video_info = ffmpeg.probe(video_path)
            video_duration = float(video_info['format']['duration'])
            
            # 检查视频是否有音频流
            has_audio = any(stream['codec_type'] == 'audio' for stream in video_info['streams'])
            
            # 获取音乐时长
            music_info = ffmpeg.probe(music_path)
            music_duration = float(music_info['format']['duration'])
            
            # 验证音乐时长
            if music_duration <= 0:
                raise Exception(f"音乐文件时长无效: {music_duration}秒")
            
            # 构建音频滤镜
            audio_filter = f'[1:a]volume={volume_ratio}'
            
            # 如果音乐需要循环播放且音乐比视频短
            if loop_music and music_duration > 0 and music_duration < video_duration:
                # 计算需要循环的次数
                loop_count = int(video_duration / music_duration) + 1
                # 创建循环音乐
                audio_filter += f',aloop=loop={loop_count}:size={int(music_duration * 44100)}'
            elif loop_music and music_duration <= 0:
                # 音乐时长为0或无效，跳过循环处理
                print(f"警告: 音乐时长为0或无效 ({music_duration})，跳过循环处理")
                logger.warning(f"警告: 音乐时长为0或无效 ({music_duration})，跳过循环处理")
            
            # 将音频裁剪到视频时长
            audio_filter += f',atrim=duration={video_duration}'
            
            # 构建FFmpeg命令
            if has_audio:
                # 视频有音频流，混合原声和背景音乐
                filter_complex = f'{audio_filter}[bg];[0:a][bg]amix=inputs=2:duration=first[mixed]'
                map_video = '-map 0:v'
                map_audio = '-map [mixed]'
            else:
                # 视频没有音频流，只使用背景音乐
                filter_complex = f'{audio_filter}[bg]'
                map_video = '-map 0:v'
                map_audio = '-map [bg]'
            
            cmd = [
                'ffmpeg',
                '-i', video_path,
                '-i', music_path,
                '-filter_complex', filter_complex,
                map_video.split(),
                map_audio.split(),
                '-c:v', 'libx264',
                '-c:a', 'aac',
                '-y', output_path
            ]
            
            # 展平命令列表
            cmd = [item for sublist in cmd for item in (sublist if isinstance(sublist, list) else [sublist])]
            
            # 执行FFmpeg命令
            result = subprocess.run(cmd, capture_output=True, text=True)
            
            if result.returncode != 0:
                raise Exception(f"FFmpeg执行失败: {result.stderr}")
            
            # 验证输出文件是否存在
            if not os.path.exists(output_path):
                raise Exception(f"FFmpeg处理完成但输出文件不存在: {output_path}")
            
            return output_path
        except Exception as e:
            raise Exception(f"添加背景音乐失败: {str(e)}")
    
    def add_background_music_with_options(self, video_path, music_path, output_dir, 
                                        volume_ratio=0.3, loop_music=True, 
                                        fade_in_duration=0, fade_out_duration=0,
                                        start_time=0, end_time=None):
        """
        为视频添加背景音乐（带更多选项）
        
        Args:
            video_path (str): 视频文件路径
            music_path (str): 背景音乐文件路径
            output_dir (str): 输出目录
            volume_ratio (float): 背景音乐音量比例，0.0-1.0，默认0.3
            loop_music (bool): 是否循环播放背景音乐，默认True
            fade_in_duration (float): 淡入时长（秒），默认0
            fade_out_duration (float): 淡出时长（秒），默认0
            start_time (float): 音乐开始时间（秒），默认0
            end_time (float): 音乐结束时间（秒），默认None（使用完整音乐）
            
        Returns:
            str: 输出视频文件路径
        """
        try:
            # 确保输出目录存在
            os.makedirs(output_dir, exist_ok=True)
            
            output_filename = f"video_with_bg_music_{uuid.uuid4().hex[:8]}.mp4"
            output_path = os.path.join(output_dir, output_filename)
            
            # 获取视频信息
            video_info = ffmpeg.probe(video_path)
            video_duration = float(video_info['format']['duration'])
            
            # 检查视频是否有音频流
            has_audio = any(stream['codec_type'] == 'audio' for stream in video_info['streams'])
            
            # 获取音乐时长
            music_info = ffmpeg.probe(music_path)
            music_duration = float(music_info['format']['duration'])
            
            # 验证音乐时长
            if music_duration <= 0:
                raise Exception(f"音乐文件时长无效: {music_duration}秒")
            
            # 构建音频滤镜
            audio_filter = f'[1:a]volume={volume_ratio}'
            
            # 添加时间段选择
            if end_time is not None:
                audio_filter += f',atrim=start={start_time}:end={end_time}'
                # 重新计算音乐时长
                music_duration = end_time - start_time
                # 验证时间段选择后的音乐时长
                if music_duration <= 0:
                    raise Exception(f"时间段选择后音乐时长无效: {music_duration}秒 (start_time={start_time}, end_time={end_time})")
            elif start_time > 0:
                audio_filter += f',atrim=start={start_time}'
                # 重新计算音乐时长
                music_duration = music_duration - start_time
                # 验证时间段选择后的音乐时长
                if music_duration <= 0:
                    raise Exception(f"时间段选择后音乐时长无效: {music_duration}秒 (start_time={start_time}, original_duration={music_duration + start_time})")
            
            # 如果音乐需要循环播放且音乐比视频短
            if loop_music and music_duration > 0 and music_duration < video_duration:
                # 计算需要循环的次数
                loop_count = int(video_duration / music_duration) + 1
                # 创建循环音乐
                audio_filter += f',aloop=loop={loop_count}:size={int(music_duration * 44100)}'
            elif loop_music and music_duration <= 0:
                # 音乐时长为0或无效，跳过循环处理
                print(f"警告: 音乐时长为0或无效 ({music_duration})，跳过循环处理")
                logger.warning(f"警告: 音乐时长为0或无效 ({music_duration})，跳过循环处理")
            
            # 添加淡入效果
            if fade_in_duration > 0:
                audio_filter += f',afade=type=in:duration={fade_in_duration}'
            
            # 添加淡出效果
            if fade_out_duration > 0:
                audio_filter += f',afade=type=out:start_time={video_duration-fade_out_duration}:duration={fade_out_duration}'
            
            # 将音频裁剪到视频时长
            audio_filter += f',atrim=duration={video_duration}'
            
            # 构建FFmpeg命令
            if has_audio:
                # 视频有音频流，混合原声和背景音乐
                filter_complex = f'{audio_filter}[bg];[0:a][bg]amix=inputs=2:duration=first[mixed]'
                map_video = '-map 0:v'
                map_audio = '-map [mixed]'
            else:
                # 视频没有音频流，只使用背景音乐
                filter_complex = f'{audio_filter}[bg]'
                map_video = '-map 0:v'
                map_audio = '-map [bg]'
            
            # 构建FFmpeg命令
            cmd = [
                'ffmpeg',
                '-i', video_path,
                '-i', music_path,
                '-filter_complex', filter_complex,
                map_video.split(),
                map_audio.split(),
                '-c:v', 'libx264',
                '-c:a', 'aac',
                '-y', output_path
            ]
            
            # 展平命令列表
            cmd = [item for sublist in cmd for item in (sublist if isinstance(sublist, list) else [sublist])]
            
            # 执行FFmpeg命令
            result = subprocess.run(cmd, capture_output=True, text=True)
            
            if result.returncode != 0:
                raise Exception(f"FFmpeg执行失败: {result.stderr}")
            
            # 验证输出文件是否存在
            if not os.path.exists(output_path):
                raise Exception(f"FFmpeg处理完成但输出文件不存在: {output_path}")
            
            return output_path
        except Exception as e:
            raise Exception(f"添加背景音乐失败: {str(e)}") 
    
    def merge_video_audio(self, video_path, audio_path, output_dir, merge_type='mix', 
                         original_volume=1.0, new_audio_volume=1.0, 
                         fade_in_duration=0, fade_out_duration=0, preview_duration=None):
        """
        合并视频和音频
        
        Args:
            video_path (str): 视频文件路径
            audio_path (str): 音频文件路径
            output_dir (str): 输出目录
            merge_type (str): 合并类型，'mix'为混合音频，'replace'为替换原音频
            original_volume (float): 原音频音量，0.0-2.0，默认1.0
            new_audio_volume (float): 新音频音量，0.0-2.0，默认1.0
            fade_in_duration (float): 淡入时长（秒），默认0
            fade_out_duration (float): 淡出时长（秒），默认0
            preview_duration (int): 预览时长（秒），None表示生成完整视频
            
        Returns:
            str: 输出视频文件路径
        """
        try:
            # 确保输出目录存在
            os.makedirs(output_dir, exist_ok=True)
            
            output_filename = f"merged_video_audio_{uuid.uuid4().hex[:8]}.mp4"
            output_path = os.path.join(output_dir, output_filename)
            
            # 获取视频信息
            video_info = ffmpeg.probe(video_path)
            video_duration = float(video_info['format']['duration'])
            
            # 检查视频是否有音频流
            has_audio = any(stream['codec_type'] == 'audio' for stream in video_info['streams'])
            
            # 获取音频时长
            audio_info = ffmpeg.probe(audio_path)
            audio_duration = float(audio_info['format']['duration'])
            
            # 如果设置了预览时长，计算实际预览时长
            actual_preview_duration = None
            if preview_duration:
                actual_preview_duration = min(preview_duration, video_duration)
                print(f"设置预览时长: {preview_duration}s -> {actual_preview_duration}s (视频总时长: {video_duration}s)")
                logging.info(f"设置预览时长: {preview_duration}s -> {actual_preview_duration}s (视频总时长: {video_duration}s)")
            
            # 构建FFmpeg命令
            if merge_type == 'replace':
                # 替换原音频模式
                if has_audio:
                    # 视频有音频流，替换音频
                    filter_complex = f'[1:a]volume={new_audio_volume}'
                    
                    # 添加淡入效果
                    if fade_in_duration > 0:
                        filter_complex += f',afade=type=in:duration={fade_in_duration}'
                    
                    # 添加淡出效果
                    if fade_out_duration > 0:
                        filter_complex += f',afade=type=out:start_time={video_duration-fade_out_duration}:duration={fade_out_duration}'
                    
                    # 将音频裁剪到视频时长
                    filter_complex += f',atrim=duration={video_duration}[new_audio]'
                    
                    cmd = [
                        'ffmpeg',
                        '-i', video_path,
                        '-i', audio_path
                    ]
                    
                    # 如果设置了预览时长，添加时间控制参数
                    if actual_preview_duration:
                        # 从视频中间部分开始
                        start_time = max(0, (video_duration - actual_preview_duration) / 2)
                        cmd.extend(['-ss', str(start_time), '-t', str(actual_preview_duration)])
                        print(f"预览时间控制: 开始时间={start_time}s, 时长={actual_preview_duration}s")
                        logging.info(f"预览时间控制: 开始时间={start_time}s, 时长={actual_preview_duration}s")
                    
                    cmd.extend([
                        '-filter_complex', filter_complex,
                        '-map', '0:v',
                        '-map', '[new_audio]',
                        '-c:v', 'libx264',
                        '-c:a', 'aac',
                        '-y', output_path
                    ])
                else:
                    # 视频没有音频流，直接添加音频
                    filter_complex = f'[1:a]volume={new_audio_volume}'
                    
                    # 添加淡入效果
                    if fade_in_duration > 0:
                        filter_complex += f',afade=type=in:duration={fade_in_duration}'
                    
                    # 添加淡出效果
                    if fade_out_duration > 0:
                        filter_complex += f',afade=type=out:start_time={video_duration-fade_out_duration}:duration={fade_out_duration}'
                    
                    # 将音频裁剪到视频时长
                    filter_complex += f',atrim=duration={video_duration}[new_audio]'
                    
                    cmd = [
                        'ffmpeg',
                        '-i', video_path,
                        '-i', audio_path
                    ]
                    
                    # 如果设置了预览时长，添加时间控制参数
                    if actual_preview_duration:
                        # 从视频中间部分开始
                        start_time = max(0, (video_duration - actual_preview_duration) / 2)
                        cmd.extend(['-ss', str(start_time), '-t', str(actual_preview_duration)])
                        print(f"预览时间控制: 开始时间={start_time}s, 时长={actual_preview_duration}s")
                        logging.info(f"预览时间控制: 开始时间={start_time}s, 时长={actual_preview_duration}s")
                    
                    cmd.extend([
                        '-filter_complex', filter_complex,
                        '-map', '0:v',
                        '-map', '[new_audio]',
                        '-c:v', 'libx264',
                        '-c:a', 'aac',
                        '-y', output_path
                    ])
            
            else:  # merge_type == 'mix'
                # 混合音频模式
                if has_audio:
                    # 视频有音频流，混合原声和新音频
                    filter_complex = f'[0:a]volume={original_volume}[orig];[1:a]volume={new_audio_volume}'
                    
                    # 添加淡入效果
                    if fade_in_duration > 0:
                        filter_complex += f',afade=type=in:duration={fade_in_duration}'
                    
                    # 添加淡出效果
                    if fade_out_duration > 0:
                        filter_complex += f',afade=type=out:start_time={video_duration-fade_out_duration}:duration={fade_out_duration}'
                    
                    # 将音频裁剪到视频时长
                    filter_complex += f',atrim=duration={video_duration}[new_audio];[orig][new_audio]amix=inputs=2:duration=first[mixed]'
                    
                    cmd = [
                        'ffmpeg',
                        '-i', video_path,
                        '-i', audio_path
                    ]
                    
                    # 如果设置了预览时长，添加时间控制参数
                    if actual_preview_duration:
                        # 从视频中间部分开始
                        start_time = max(0, (video_duration - actual_preview_duration) / 2)
                        cmd.extend(['-ss', str(start_time), '-t', str(actual_preview_duration)])
                        print(f"预览时间控制: 开始时间={start_time}s, 时长={actual_preview_duration}s")
                        logging.info(f"预览时间控制: 开始时间={start_time}s, 时长={actual_preview_duration}s")
                    
                    cmd.extend([
                        '-filter_complex', filter_complex,
                        '-map', '0:v',
                        '-map', '[mixed]',
                        '-c:v', 'libx264',
                        '-c:a', 'aac',
                        '-y', output_path
                    ])
                else:
                    # 视频没有音频流，只使用新音频
                    filter_complex = f'[1:a]volume={new_audio_volume}'
                    
                    # 添加淡入效果
                    if fade_in_duration > 0:
                        filter_complex += f',afade=type=in:duration={fade_in_duration}'
                    
                    # 添加淡出效果
                    if fade_out_duration > 0:
                        filter_complex += f',afade=type=out:start_time={video_duration-fade_out_duration}:duration={fade_out_duration}'
                    
                    # 将音频裁剪到视频时长
                    filter_complex += f',atrim=duration={video_duration}[new_audio]'
                    
                    cmd = [
                        'ffmpeg',
                        '-i', video_path,
                        '-i', audio_path
                    ]
                    
                    # 如果设置了预览时长，添加时间控制参数
                    if actual_preview_duration:
                        # 从视频中间部分开始
                        start_time = max(0, (video_duration - actual_preview_duration) / 2)
                        cmd.extend(['-ss', str(start_time), '-t', str(actual_preview_duration)])
                        print(f"预览时间控制: 开始时间={start_time}s, 时长={actual_preview_duration}s")
                        logging.info(f"预览时间控制: 开始时间={start_time}s, 时长={actual_preview_duration}s")
                    
                    cmd.extend([
                        '-filter_complex', filter_complex,
                        '-map', '0:v',
                        '-map', '[new_audio]',
                        '-c:v', 'libx264',
                        '-c:a', 'aac',
                        '-y', output_path
                    ])
            
            # 执行FFmpeg命令
            result = subprocess.run(cmd, capture_output=True, text=True)
            
            if result.returncode != 0:
                raise Exception(f"FFmpeg执行失败: {result.stderr}")
            
            # 验证输出文件是否存在
            if not os.path.exists(output_path):
                raise Exception(f"FFmpeg处理完成但输出文件不存在: {output_path}")
            
            return output_path
        except Exception as e:
            raise Exception(f"视频音频合并失败: {str(e)}") 